package com.usian.service.Impl;

import com.github.pagehelper.PageHelper;
import com.usian.mapper.SearchItemMapper;
import com.usian.pojo.SearchItem;
import com.usian.service.SearchItemService;
import com.usian.utils.JsonUtils;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.get.GetIndexRequest;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.IndicesClient;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @author chen
 * @date 2021/1/19 - 10:39 - 星期二
 * @project usian_parent
 * @package com.usian.service.Impl
 * @by GGbomd猪猪侠
 */
@Service
@Transactional
public class SearchItemServiceImpl implements SearchItemService {

    @Autowired
    private SearchItemMapper searchItemMapper;

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    //注入索引库名称
    @Value("${ES_INDEX_NAME}")
    private String ES_INDEX_NAME;

    //注入表名称
    @Value("${ES_TYPE_NAME}")
    private String ES_TYPE_NAME;

    /**
     * 导入商品库到Elasticsearch
     * 操作 tb_item  tb_item_cat  tb_item_desc 表
     * @return
     */
    @Override
    public Boolean importAll() {
        try {
            // 再将查询到的数据存到elasticsearch索引库中
            // 创建索引库 表 和 字段
            // 判断索引库是否存在
            if (!isExistsIndex()){
                createIndex();
            }
            int page = 1 ;

            while (true){
                /**分页每次导入一千条*/
                PageHelper.startPage(page,1000);
                // 先查询到数据库中的sql
                List<SearchItem> searchItems = searchItemMapper.getItemList();
                // 知道取完集合里的数据 跳出当此循环
                if (searchItems == null || searchItems.size() == 0){
                    break;
                }
                //批量添加
                BulkRequest bulkRequest = new BulkRequest();
                for (int i = 0; i < searchItems.size(); i++) {
                    SearchItem searchItem = searchItems.get(i);
                    System.out.println(searchItems.toString()+"***");
                    //把商品中的信息添加到es中
                    IndexRequest indexRequest = new IndexRequest(ES_INDEX_NAME,ES_TYPE_NAME);
                    bulkRequest.add(indexRequest.source(JsonUtils.objectToJson(searchItem),XContentType.JSON));
                }
                restHighLevelClient.bulk(bulkRequest,RequestOptions.DEFAULT);
                page++;
            }
            return true;
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 索引库是否存在
     * 如果创建了返回一个true 否则返回一个false
     * @return
     * @throws IOException
     */
    private Boolean isExistsIndex() throws IOException {
        GetIndexRequest getIndexRequest = new GetIndexRequest();
        getIndexRequest.indices(ES_INDEX_NAME);
        return restHighLevelClient.indices().exists(getIndexRequest,RequestOptions.DEFAULT);
    }

    /**
     * 创建索引库
     * @return
     * @throws IOException
     */
    private boolean createIndex() throws IOException {
        // /创建索引请求对象，并设置索引名称
        CreateIndexRequest createIndexRequest = new CreateIndexRequest(ES_INDEX_NAME);
        // 设置索引参数
        createIndexRequest.settings("{\n" +
                "    \"number_of_shards\": 2,\n" +   //分成两片
                "    \"number_of_replicas\": 1\n" +
                "  }", XContentType.JSON);
        //创建索引库的表和字段
        createIndexRequest.mapping(ES_TYPE_NAME,"{\n" +
                "  \"_source\": { \n" +
                "    \"excludes\": [\n" +
                "      \"itemDesc\"\n" +
                "    ]\n" +
                "  },\n" +
                "  \"properties\": {\n" +
                "    \"itemTitle\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    },\n" +
                "    \"itemSellPoint\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    },\n" +
                "    \"itemPrice\": {\n" +
                "      \"type\": \"float\"\n" +
                "    },\n" +
                "    \"itemImage\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"index\": false\n" +
                "    },\n" +
                "    \"itemCategoryName\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    },\n" +
                "    \"itemDesc\": {\n" +
                "      \"type\": \"text\",\n" +
                "      \"analyzer\": \"ik_max_word\",\n" +
                "      \"search_analyzer\": \"ik_smart\"\n" +
                "    }\n" +
                "  }\n" +
                "}",XContentType.JSON);
        //创建索引操作客户端
        IndicesClient indices = restHighLevelClient.indices();
        // 创建响应对象
        CreateIndexResponse createIndexResponse = indices.create(createIndexRequest, RequestOptions.DEFAULT);
        // 得到响应
        return createIndexResponse.isAcknowledged();
    }

    /**
     * 首页搜索 分页查询名字、类别、描述、卖点包含q的商品
     * @param q 搜索条件
     * @param page 第几页
     * @param pageSize  显示几条
     * @return
     */
    @Override
    public List<SearchItem> selectByq(String q, Integer page, Integer pageSize) {
        try {
            //搜索请求对象 索引名和表名
            SearchRequest searchRequest = new SearchRequest(ES_INDEX_NAME);
            searchRequest.types(ES_TYPE_NAME);
            // 设置需要搜索的字段
            SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
            //1、查询名字、描述、卖点、类别包括“q”的商品
            searchSourceBuilder.query(QueryBuilders.multiMatchQuery(q,new String[]{
                    "itemTitle","itemDesc","itemSellPoint","itemCategoryName"}));
            // 2分页
            /**
             * 1  0  20--->(p-1)*pageSize
             * 2  20 20--->(2-1)*20
             * 3  40 20--->(3-1)*20
             */
            Integer form = (page-1)*pageSize;
            searchSourceBuilder.from(form);
            searchSourceBuilder.size(pageSize);

            // 3. 设置高亮字段
            HighlightBuilder highlightBuilder = new HighlightBuilder();
            highlightBuilder.preTags("<font color='red'>");
            highlightBuilder.postTags("</font>");
            highlightBuilder.field("itemTitle");
            searchSourceBuilder.highlighter(highlightBuilder);
            searchRequest.source(searchSourceBuilder);
            SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            // 匹配搜索到的结果和文档
            SearchHit[] hits = response.getHits().getHits();
            //4、返回查询结果
            List<SearchItem> searchItems= new ArrayList<>();
            for (int i = 0; i < hits.length; i++) {
                // 取到每条结果
                SearchHit hit = hits[i];
                // 把查出来的结果转换成json格式
                SearchItem searchItem = JsonUtils.jsonToPojo(hit.getSourceAsString(), SearchItem.class);
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                if (highlightFields != null && highlightFields.size() > 0){
                    searchItem.setItemTitle(highlightFields.get("itemTitle").getFragments()[0].toString());
                }
                searchItems.add(searchItem);
            }
            return searchItems;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    // rabbitmq  对列
    @Override
    public int insertDocument(String msg) throws IOException {
        // 1、根据商品id查询商品信息。
        SearchItem searchItem = searchItemMapper.getItemById(Long.valueOf(msg));

        //2、添加商品到索引库
        IndexRequest indexRequest = new IndexRequest(ES_INDEX_NAME, ES_TYPE_NAME);
        indexRequest.source(JsonUtils.objectToJson(searchItem), XContentType.JSON);
        IndexResponse indexResponse =
                restHighLevelClient.index(indexRequest,RequestOptions.DEFAULT);
        return indexResponse.getShardInfo().getFailed();
    }
}
